# 'Friendly Flow' is a Server Framework for Python 2.5 and up
# Copyright (C) Xaba Software http://www.xaba.nl/
#
# This file is part of 'Friendly Flow'
#
# 'Friendly Flow' is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 'Friendly Flow' is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with 'Friendly Flow'; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

from socket import socket as python_socket, error as SocketError

from friendlyflow import read, write, RETURN

RECV_SIZE = 4096

OPERATION_NOW_IN_PROGRESS = 115

class socket(object):
    
    def __init__(self, sock=None):
        """param sock is a python socket.Socket object"""
        if sock == None:
            sock = python_socket()
        self._sock = sock
        self._sock.setblocking(0)

    def __getattr__(self, attr):
        return getattr(self._sock, attr)

    def connect(self, address):
        try:
            self._sock.connect(address)
        except SocketError, e:
            if not e.args[0] == OPERATION_NOW_IN_PROGRESS:
                raise
    
    def accept(self):
        yield read(self._sock)
        newConnection, address = self._sock.accept()
        yield RETURN((newConnection, address))

    def read(self, bytes):
        """May return up to bytes bytes"""
        yield read(self._sock)
        yield RETURN(self._sock.recv(bytes))
        
    def readAll(self, bytes):
        """Will return exactly bytes bytes"""
        result = ''
        diff = bytes - len(result)
        while diff:
            yield read(self._sock)
            result += self._sock.recv(diff)
            diff = bytes - len(result)
        yield RETURN(result)
    
    def write(self, data):
        """May write a part of data. The length of the written data is returned"""
        yield write(self._sock)
        yield RETURN(self._sock.send(data))

    def writeAll(self, data):
        writtenNow = 0
        writtenTotal = 0
        toDo = len(data)
        while writtenTotal < toDo:
            yield write(self._sock)
            if writtenNow:
                data = data[writtenNow:]
            writtenNow = self._sock.send(data)
            writtenTotal +=  writtenNow
        yield RETURN(writtenTotal)
        
class LineReader(object):

    def __init__(self, sock=None):
        """param sock is a friendlyflow socket object"""
        if sock == None:
            sock = socket()
        self._sock = sock
        self._buffer = ''

    def __getattr__(self, attr):
        return getattr(self._sock, attr)

    def readLine(self):
        while not '\r\n' in self._buffer:
            self._buffer += yield self._sock.read(RECV_SIZE)
        left, self._buffer = self._buffer.split('\r\n', 1)
        yield RETURN(left)
        
    def readAll(self, bytes):
        if len(self._buffer) <= bytes:
            result = self._buffer[:bytes]
            self._buffer = self._buffer[bytes:]
            yield RETURN(result)
        else:
            rest = yield self._sock.readAll(bytes - len(self._buffer))
            self._buffer = ''
            yield RETURN(self._buffer + rest)

#todo: use recv_into(